package com.ashlikun.customdialog

import android.R
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.Window
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.viewbinding.ViewBinding
import java.lang.reflect.AccessibleObject
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.lang.reflect.Modifier

/**
 * 作者　　: 李坤
 * 创建时间: 2022/4/23　12:04
 * 邮箱　　：496546144@qq.com
 *
 * 功能介绍：
 */
internal object DialogUtils {
    /**
     * 全局当Activity 调用 setSafeArea 的时候,可以修改全局设置
     */
    var onSetSafeArea: (dialog: BaseDialog) -> Unit = { dialog ->
        if ((dialog.requireWindow.attributes.gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
            val isNightMode = (dialog.context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
            enableEdgeToEdge(dialog.requireWindow, true, isNightMode)
        } else {
            enableEdgeToEdge(dialog.requireWindow, true, true)
        }
        val view = dialog.requireWindow.decorView
        if ((dialog.requireWindow.attributes.gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
            setSafeAreaPadding(view, top = false)
        } else {
            setSafeAreaPadding(view)
        }
    }

    fun dip2px(context: Context, dipValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dipValue * scale + 0.5f).toInt()
    }

    fun screenHeight(context: Context) = context.resources.displayMetrics.heightPixels

    private var viewBindingGetMap = mutableMapOf<Class<*>, AccessibleObject>()

    /**
     * 获取Bar高度
     */
    fun getActionBarSize(context: Context): Int {
        val styledAttributes = context.theme.obtainStyledAttributes(intArrayOf(R.attr.actionBarSize))
        val barHeight = styledAttributes.getDimension(0, 0f).toInt()
        styledAttributes.recycle()
        return barHeight
    }

    /**
     * 获得状态栏的高度
     */
    fun getStatusHeight(context: Context): Int {
        var result = 0
        val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) {
            result = context.resources.getDimensionPixelSize(resourceId)
        }
        return result
    }

    /**
     * 方法功能：从context中获取activity，如果context不是activity那么久返回null
     */
    fun getActivity(context: Context?): Activity? {
        if (context == null) {
            return null
        }
        if (context is Activity) {
            return context
        } else if (context is ContextWrapper) {
            return getActivity(context.baseContext)
        } else if (context is ContextThemeWrapper) {
            return getActivity(context.baseContext)
        }
        return null
    }


    /**
     * 反射查找ViewBinding的view
     *
     * @return 实例是ViewBinding
     */
    fun getViewBinding(`object`: Any?): ViewBinding? {
        if (`object` == null) {
            return null
        }
        try {
            //检测是否有ViewBinding 库
            val viewBindingCls: Class<*> = ViewBinding::class.java
            val objCls: Class<*> = `object`.javaClass
            //查找缓存
            var accessibleObject = viewBindingGetMap[objCls]
            if (accessibleObject != null) {
                accessibleObject.isAccessible = true
                if (accessibleObject is Method) {
                    return accessibleObject.invoke(`object`) as ViewBinding
                } else if (accessibleObject is Field) {
                    return accessibleObject[`object`] as ViewBinding
                }
            }
            var cls: Class<*>? = objCls
            while (cls != null && cls != Any::class.java) {
                //获取方法->返回值是
                val declaredMethods = cls.declaredMethods
                for (m in declaredMethods) {
                    if (viewBindingCls.isAssignableFrom(m.returnType)) {
                        m.isAccessible = true
                        val view = m.invoke(`object`) as ViewBinding
                        viewBindingGetMap[objCls] = m
                        return view
                    }
                }
                //获取父类的
                cls = cls.superclass
            }
        } catch (e: Exception) {
            return null
        } catch (e: NoClassDefFoundError) {
            return null
        }
        return null
    }


    /**
     * 获取3个参数的静态方法
     * @return ViewBinding
     */
    fun getViewBindingToClass(
        cls: Class<*>?,
        layoutInflater: LayoutInflater?,
        parent: ViewGroup?,
        attachToParent: Boolean
    ): Any? {
        if (cls == null || layoutInflater == null) {
            return null
        }
        //从缓存获取
        try {
            var inflate: Method? = null
            val existinflate = viewBindingGetMap[cls]
            if (existinflate is Method) {
                inflate = existinflate
            }
            if (inflate == null) {
                //直接取方法
                inflate = cls.getDeclaredMethod(
                    "inflate",
                    LayoutInflater::class.java,
                    ViewGroup::class.java,
                    Boolean::class.javaPrimitiveType
                )
                //这里循环全部方法是为了混淆的时候无影响
                if (inflate == null) {
                    val declaredMethods = cls.declaredMethods
                    for (declaredMethod in declaredMethods) {
                        val modifiers = declaredMethod.modifiers
                        if (Modifier.isStatic(modifiers)) {
                            val parameterTypes = declaredMethod.parameterTypes
                            if (parameterTypes != null && parameterTypes.size == 3) {
                                if (LayoutInflater::class.java.isAssignableFrom(parameterTypes[0]) &&
                                    ViewGroup::class.java.isAssignableFrom(parameterTypes[1]) &&
                                    Boolean::class.javaPrimitiveType!!.isAssignableFrom(
                                        parameterTypes[2]
                                    )
                                ) {
                                    inflate = declaredMethod
                                    break
                                }
                            }
                        }
                    }
                }
                //添加到缓存
                if (inflate != null) {
                    viewBindingGetMap[cls] = inflate
                }
            }
            if (inflate != null) {
                return inflate.invoke(null, layoutInflater, parent, attachToParent)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    inline fun getViewSize(view: View?, crossinline onSizeListener: (width: Int, height: Int) -> Unit) {
        view?.run {
            if (measuredWidth > 0 || measuredHeight > 0) {
                onSizeListener.invoke(measuredWidth, measuredHeight)
                return
            }
            val observer = viewTreeObserver
            observer.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    if (measuredHeight <= 0 && measuredWidth <= 0) {
                        return
                    }
                    viewTreeObserver.removeOnGlobalLayoutListener(this)
                    onSizeListener.invoke(width, height)
                }
            })
        }

    }

    fun setSafeAreaPadding(view: View, top: Boolean = true, bottom: Boolean = true, consume: Boolean = true) {
        //这里会动态返回用户设置的底部高度
        ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
            val systemBars = insets.systemWindowInsets
//        val statusBars = insets.getInsets(WindowInsetsCompat.Type.statusBars())
//        val navigationBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
            //更新背景视图位置和尺寸
            if (top) view.setPadding(view.paddingLeft, systemBars.top, view.paddingRight, view.paddingBottom)
            if (bottom) view.setPadding(view.paddingLeft, view.paddingTop, view.paddingRight, systemBars.bottom)
            //返回消耗的insets
            if (consume) {
                insets.replaceSystemWindowInsets(systemBars.left, 0, systemBars.right, 0)
            } else {
                insets
            }
        }
    }

    //参照WindowCompat.enableEdgeToEdge
    fun enableEdgeToEdge(
        window: Window,
        statusBarIsDark: Boolean,
        navigationBarIsDark: Boolean,
    ) {
        // This triggers the initialization of the decor view here to prevent the attributes set by
        // this method from getting overwritten by the initialization later.
        window.decorView
        WindowCompat.setDecorFitsSystemWindows(window, false)
        window.statusBarColor = Color.TRANSPARENT
        window.navigationBarColor = Color.TRANSPARENT
        if (Build.VERSION.SDK_INT >= 28) {
            val newMode = if (Build.VERSION.SDK_INT >= 30)
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
            else
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
            val attrs = window.attributes
            if (attrs.layoutInDisplayCutoutMode != newMode) {
                attrs.layoutInDisplayCutoutMode = newMode
                window.attributes = attrs
            }
        }
        window.isStatusBarContrastEnforced = false
        window.isNavigationBarContrastEnforced = false
        WindowInsetsControllerCompat(window, window.decorView).run {
            isAppearanceLightStatusBars = !statusBarIsDark
            isAppearanceLightNavigationBars = !navigationBarIsDark
        }
    }
}